package org.cncy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;


public class DesEncryptUtil {
    private static Logger Log = LoggerFactory.getLogger(DesEncryptUtil.class);

    //客户端密钥
    private static final byte[] SECRET_KEY_NORMAL = digest("nq");

    //服务端密钥
    //private static final byte[] SECRET_KEY_NORMAL = digest("NQ_license^Sky");
    private static final byte[] COMPRESS_HEADER = digest("nq_pineapple_backup_compress");

    /**
     * 字符串加密
     */
    public static String encrypt(String value) {
        if (value == null)
            return null;
        byte[] bytes = value.getBytes();

        try {
            int keySpilt = SECRET_KEY_NORMAL.length / 2;
            byte[] key = new byte[keySpilt];
            byte[] iv = new byte[keySpilt];
            System.arraycopy(SECRET_KEY_NORMAL, 0, key, 0, keySpilt);
            System.arraycopy(SECRET_KEY_NORMAL, keySpilt, iv, 0, keySpilt);

            SecretKey securekey = SecretKeyFactory.getInstance("DES")
                    .generateSecret(new DESKeySpec(key));
            AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(iv);

            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");// 得到加密对象Cipher
            cipher.init(Cipher.ENCRYPT_MODE, securekey, ivParameterSpec);// 设置工作模式为加密模式，给出密钥和向量
            bytes = cipher.doFinal(bytes);

        } catch (Exception e) {
            Log.error("Utils>>encrypt", "des failer:", e);
            return "";
        }
        return new String(NqBase64Util.encodeBase64(bytes));
    }

    /**
     * 字符串解密
     */
    public static String decrypt(String encValue) {
        if ("".equals(encValue))
            return "";
        byte[] bytes = NqBase64Util.decodeBase64(encValue.getBytes());
        if (bytes == null)
            return "";

        try {
            int keySpilt = SECRET_KEY_NORMAL.length / 2;
            byte[] key = new byte[keySpilt];
            byte[] iv = new byte[keySpilt];
            System.arraycopy(SECRET_KEY_NORMAL, 0, key, 0, keySpilt);
            System.arraycopy(SECRET_KEY_NORMAL, keySpilt, iv, 0, keySpilt);

            AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            SecretKey securekey = SecretKeyFactory.getInstance("DES")
                    .generateSecret(new DESKeySpec(key));

            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, securekey, ivParameterSpec);
            bytes = cipher.doFinal(bytes);
            if (bytes == null)
                return "";
            return new String(bytes, "UTF-8");
        } catch (Exception e) {
            Log.error("Utils>>decrypt", "des failer:", e);
            return "";
        }
    }

    /**
     * 加密文件
     */
    public static boolean encryptFile(File srcFile, File destFile) {
        if (srcFile == null || !srcFile.exists() || srcFile.isDirectory()
                || destFile == null
                || (destFile.exists() && destFile.isDirectory())) {
            return false;
        }

        try {
            final int keySpilt = SECRET_KEY_NORMAL.length / 2;
            final byte[] key = new byte[keySpilt];
            final byte[] iv = new byte[keySpilt];
            System.arraycopy(SECRET_KEY_NORMAL, 0, key, 0, keySpilt);
            System.arraycopy(SECRET_KEY_NORMAL, keySpilt, iv, 0, keySpilt);

            final SecretKey securekey = SecretKeyFactory.getInstance("DES")
                    .generateSecret(new DESKeySpec(key));
            final AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(
                    iv);

            final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");// 得到加密对象Cipher
            cipher.init(Cipher.ENCRYPT_MODE, securekey, ivParameterSpec);// 设置工作模式为加密模式，给出密钥和向量

            final InputStream is = new FileInputStream(srcFile);
            final GZIPOutputStream out = new GZIPOutputStream(
                    new FileOutputStream(destFile));
            final CipherInputStream cis = new CipherInputStream(is, cipher);

            out.write(COMPRESS_HEADER, 0, COMPRESS_HEADER.length);
            final byte[] buffer = new byte[1024];
            int r;
            while ((r = cis.read(buffer)) > 0) {
                out.write(buffer, 0, r);
            }
            cis.close();
            is.close();
            out.close();

            return true;
        } catch (Exception e) {
            Log.error("Utils>>encryptFile", "des failer:" + e.getMessage(), e);
            return false;
        }
    }

    /**
     * 解密文件
     */
    public static boolean decryptFile(File srcFile, File destFile) {
        try {
            final int keySpilt = SECRET_KEY_NORMAL.length / 2;
            final byte[] key = new byte[keySpilt];
            final byte[] iv = new byte[keySpilt];
            System.arraycopy(SECRET_KEY_NORMAL, 0, key, 0, keySpilt);
            System.arraycopy(SECRET_KEY_NORMAL, keySpilt, iv, 0, keySpilt);

            final AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(
                    iv);
            final SecretKey securekey = SecretKeyFactory.getInstance("DES")
                    .generateSecret(new DESKeySpec(key));

            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, securekey, ivParameterSpec);

            final InputStream is = new GZIPInputStream(new FileInputStream(
                    srcFile));
            final OutputStream out = new FileOutputStream(destFile);
            final CipherOutputStream cos = new CipherOutputStream(out, cipher);
            byte[] header = new byte[COMPRESS_HEADER.length];
            is.read(header, 0, COMPRESS_HEADER.length);

            if (!checkBA(header, COMPRESS_HEADER)) {
                cos.write(header, 0, header.length);
            }
            final byte[] buffer = new byte[1024];
            int r;
            while ((r = is.read(buffer)) >= 0) {
                cos.write(buffer, 0, r);
            }
            cos.close();
            out.close();
            is.close();
            return true;
        } catch (Exception e) {
            Log.error("Utils>>decryptFile", "des failer:" + e.getMessage(), e);
            return false;
        }
    }

    /**
     * 检查两个字节数组是否相同
     *
     * @param src
     * @param dest
     * @return
     */
    public static boolean checkBA(byte[] src, byte[] dest) {
        if (src.length != dest.length)
            return false;
        for (int i = 0; i < src.length; i++) {
            if (src[i] != dest[i])
                return false;
        }
        return true;
    }

    /**
     * MD5加密
     */
    public static byte[] digest(String text) {
        try {
            byte[] b = MessageDigest.getInstance("md5").digest(text.getBytes());
            return b;
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
}
